/*Class for store, control and draw a circle set
when shuffle, the circle will move from the original location 
to the new location along a bezier curve. 
The stroke and radius will also change accordingly.
*/

class CircleList {
  ArrayList circleArray;  //store all circles
  ArrayList motionTrace;  //array to record the bezier trace for each circle
  int circleNum;  // circle number
  int motionCounter;  //a counter indicates current moving status. should less than the bezierNum
  int bezierNum;  //density of dots along the motion trace. For motion use. More bezierPoints means smoother the transition
  boolean bShuffle;  //shuffle status. False means no shuffle.
  int showMode;  //display mode
  
  CircleList() {
    circleArray = new ArrayList<Circle>();
    circleNum = (int)random(2,8);  //generate circle numbers
    for (int i=0;i<circleNum;i++) {  //initialize all circles
      float tempR = random(10,100);
      circleArray.add( new Circle(random(tempR,width-tempR), random(tempR,height-tempR),tempR,(int)random(1,10)));
    }
    bShuffle = false;
    motionCounter = 0;  
    bezierNum = 50;  //default motion steps is 50. means from the current location to the new location need to draw about 50 times
    showMode = 0;
  }
  
  void setShowMode(int t) {//set display mode
    showMode = t;
  }
  
  void shuffle() {  //initialize shuffle mode
    motionCounter = 0;  //make zero each time
    bShuffle = true;  //turn to shuffle mode so that will draw the shufflemove
    
    ArrayList finalPoint = new ArrayList<PVector>();  //store all new locations for each circle
    for(int i=0; i<circleArray.size(); i++) {  //generate new center points of circles
      finalPoint.add(new PVector(random(0,width), random(0,height)));
    }
    ArrayList bezierPoints;  //array to store all bezierPoints along the bezier trace.
    motionTrace = new ArrayList<ArrayList>();  // array to store all traces' bezierPoints
    for(int i=0; i<circleArray.size(); i++) {  //for each circle
      PVector tp1 = new PVector(random(0,width),random(0,height));  //generate two bezier curve control points tp1 tp2
      PVector tp2 = new PVector(random(0,width),random(0,height));
      bezierPoints = new ArrayList<PVector>();  
      for(int j=0; j<bezierNum; j++) {  //calculate all bezierPoints along the curve and push into the points array
        float t = j / float(bezierNum);
        float tpx = bezierPoint(((Circle)circleArray.get(i)).location.x, tp1.x, ((PVector)finalPoint.get(i)).x, tp2.x, t);
        float tpy = bezierPoint(((Circle)circleArray.get(i)).location.y, tp1.y, ((PVector)finalPoint.get(i)).y, tp2.y, t);
        bezierPoints.add(new PVector(tpx,tpy));
      }
      motionTrace.add(bezierPoints);  //for all points array, push to the motionTrace

    }
  }
  
  void shuffleMove() {  //call when shuffle is truiggered, till finish moving
    if(motionCounter<bezierNum-1) {  //if the moving hasn't done
      motionCounter++;
    }
    else {
      bShuffle = false;  //already move to the new location, turn to normal drawing mode
    }
    
    for(int i=0; i<circleArray.size(); i++) {  //drawing new circles for each motion step
      ((Circle)circleArray.get(i)).location.x = ((PVector)((ArrayList)motionTrace.get(i)).get(motionCounter)).x;
      ((Circle)circleArray.get(i)).location.y = ((PVector)((ArrayList)motionTrace.get(i)).get(motionCounter)).y;
      ((Circle)circleArray.get(i)).radius = map(((Circle)circleArray.get(i)).location.x,0, width, 10,100);
      ((Circle)circleArray.get(i)).weight = (int)map(((Circle)circleArray.get(i)).location.y,0, height, 1,10);
    } 
  }
  
  void draw() {
    if(!bShuffle) {
      for(int i=0;i<circleNum;i++) {
        ((Circle)circleArray.get(i)).draw(showMode);
      }
    }
    else {
      shuffleMove();
      for(int i=0;i<circleNum;i++) {
        ((Circle)circleArray.get(i)).draw(showMode);
      }
    }
  }
}
